# Feature Toggling

Feature toggling is enabled by Puck's [Permissions API](/docs/api-reference/permissions). This enables you to toggle behavior like:

- Deletion
- Dragging
- Duplication
- Editing (setting all fields to read-only)
- etc

See the [supported permissions reference](/docs/api-reference/permissions#supported-permissions) for a complete list.

## Toggling features globally

Toggling features across the entire Puck instance can be done with global permissions. These can be set by the [`permissions` prop](/docs/api-reference/components/puck#permissions) on the Puck component:

```tsx showLineNumbers copy {4-6}
export function Editor() {
  return (
    <Puck
      permissions={{
        delete: false, // Disable delete function on all components
      }}
      // ...
    />
  );
}
```

## Toggling features per component

Toggling feature for all instance of a component can be done using component permissions. This is controlled by the [`permissions` parameter](/docs/api-reference/configuration/component-config#permissions) on the component config, and inherits the global permissions.

```tsx showLineNumbers copy {4-6}
const config = {
  components: {
    HeadingBlock: {
      permissions: {
        delete: false, // Disable delete function on all HeadingBlock instances
      },
      // ...
    },
  },
};
```

Component permissions can also be applied to the `root` config.

## Toggling features dynamically

Dynamic permissions enable runtime calculation of permissions based on the component data, enabling instance-specific permissions. This is controlled by the [`resolvePermissions` parameter](/docs/api-reference/configuration/component-config#resolvepermissionsdata-params) on the component config.

```tsx showLineNumbers copy {4-12}
const config = {
  components: {
    HeadingBlock: {
      resolvePermissions: (data, { permissions }) => {
        if (data.props.locked) {
          return {
            delete: false, // Disable delete function when HeadingBlock `locked` prop is set
          };
        }

        return permissions; // Return inherited permissions (component or global)
      },
      // ...
    },
  },
};
```

### Asynchronous feature toggling

Permissions can be resolved asynchronously, enabling powerful patterns like querying permissions from an endpoint whenever the data changes.

```tsx showLineNumbers copy {4-8}
const config = {
  components: {
    HeadingBlock: {
      resolvePermissions: async (data) => {
        const serverPermissions = await myPermissionsApi(data.props.id); // Query permissions from a server

        return serverPermissions;
      },
      // ...
    },
  },
};
```

### Preventing duplicate calls

Permission resolvers are cached based on the component props. If none of the props change, then the resolver won't be called. This prevents duplicate calls to expensive asynchronous operations.

However, it's possible that you may want to avoid making an expensive operation unless a _specific_ prop has changed, rather than any prop.

This can be restricted by checking the [`changed` param](/docs/api-reference/configuration/component-config#paramschanged-2) before calling any expensive operations.

```tsx {6} showLineNumbers copy
const config = {
  components: {
    HeadingBlock: {
      // ...
      resolvePermissions: async (data, { changed, lastPermissions }) => {
        if (!changed.locked) return lastPermissions; // Return last permissions if `locked` hasn't changed

        return await myExpensivePermissionsApi(data),
      },
      // ...
    },
  },
};
```

## Further reading

- [Permissions API reference](/docs/api-reference/permissions)
- [Supported permissions reference](/docs/api-reference/permissions#supported-permissions)
- [Global `permissions` prop API reference](/docs/api-reference/components/puck#permissions)
- [Component `permissions` param API reference](/docs/api-reference/configuration/component-config#permissions)
- [Component `resolvePermissions` param API reference](/docs/api-reference/configuration/component-config#resolvepermissionsdata-params)
